package com.nariano.server.utils.aop.rwsemaphore;

import java.util.ConcurrentModificationException;
import java.util.logging.Logger;


import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

@Aspect
public class ReadWriteSemaphoreAspect {
	
	volatile int reads = 0;
	volatile int writes = 0;
	
	private static Logger logger = Logger.getLogger(ReadWriteSemaphoreAspect.class.getCanonicalName());

	@Autowired
    @Qualifier(value = "semaphore")
	private Semaphore semaphore;

	@Pointcut("@annotation(com.nariano.server.utils.aop.rwsemaphore.ReadTransaction)")
	public void readOperation() {
	}

	@Pointcut("@annotation(com.nariano.server.utils.aop.rwsemaphore.WriteTransaction)")
	public void writeOperation() {
	}

	@Around("com.nariano.server.utils.aop.rwsemaphore.ReadWriteSemaphoreAspect.readOperation()")
	public Object doRead(ProceedingJoinPoint pjp) throws Throwable {

		try {
			semaphore.acquireRead();
			reads++;
			Object retVal = pjp.proceed();
			return retVal;
		} catch(ConcurrentModificationException e) {
			logger.severe(String.format("Reads=%d Writes=%d %s", reads, writes, semaphore.toString()));
			throw e;
		} finally {
			semaphore.releaseRead();
			reads--;
		}
	}

	@Around("com.nariano.server.utils.aop.rwsemaphore.ReadWriteSemaphoreAspect.writeOperation()")
	public Object doWrite(ProceedingJoinPoint pjp) throws Throwable {

		try {
			semaphore.acquireWrite();
			writes++;
			Object retVal = pjp.proceed();
			return retVal;
		} catch(ConcurrentModificationException e) {
			logger.severe(String.format("Reads=%d Writes=%d %s", reads, writes, semaphore.toString()));
			throw e;
		}finally {
			semaphore.releaseWrite();
			writes--;
		}
	}

}

